using UnityEngine;
using System.Collections.Generic;
using System;
using JetBrains.Annotations;
using UBlockly.Scriptable;
using UBlockly.UI;
using UBlockly.Sys;
using UBlockly.Util;
using UBlockly.Compotent;
using UBlockly.Graphic;

namespace UBlockly
{
    public class BlockFramework
    {
        private static bool isInit = false;
        private static BlockFramework instance = new BlockFramework();
        private BlockLoaderSystem loaderSys;
        private SoundHelper blockSound = new SoundHelper();
        private BlockResource blockResource = new BlockResource();
        private BlockTipUIPanel blockTipPanel;
        private GameObject EmptyGo;
        private Dictionary<int, UBlockEntry> wholeEntries;

        internal static SoundHelper Sound => instance.blockSound;

        private BlockFramework()
        {
            loaderSys = new BlockLoaderSystem();
            wholeEntries = new Dictionary<int, UBlockEntry>();
            EmptyGo = new GameObject("BlockFrameworkGo");
            blockTipPanel = new GameObject("BlockTipPanel").AddComponent<BlockTipUIPanel>();
            blockTipPanel.gameObject.transform.SetParent(EmptyGo.transform);
            GameObject.DontDestroyOnLoad(EmptyGo);
            GraphicHelper.InitGraphic(blockResource);
        }

        void InitResource(string path)
        {
            isInit = true;
            var graphicPath = $"{path}/BlockGraphic.asset";
            if (!System.IO.File.Exists(graphicPath))
                throw new SystemException("Block InitGraphic error,doesnot exist file:" + graphicPath);
            LoadResource<BlockGraphicAsset>(graphicPath, asset =>
            {
                blockResource.SetGraphicAsset(asset);
                blockTipPanel.InitSetterPanel();
            });
            LoadResource<BlockSoundAsset>($"{path}/BlockSound.asset", asset => { blockResource.SetSoundAsset(asset); });
        }

        internal static GameObject GetFrameworkGo()
        {
            return instance.EmptyGo;
        }

        internal static BlockTipUIPanel BlockTipPanel => instance.blockTipPanel;

        public static void InitFramework(IBlockLoader loader)
        {
            if (isInit)
                return;
            isInit = true;
            instance.blockSound.Init(instance.EmptyGo);
            instance.loaderSys.SetLoaderAgent(loader);
            instance.InitResource(loader.CustomConfigPath);
            ILTranslate.Init();
        }

        public static void SetTipPanel(Transform transform)
        {
            instance.blockTipPanel.transform.SetParent(transform);
            instance.blockTipPanel.transform.localPosition = Vector3.zero;
            instance.blockTipPanel.transform.localScale = Vector3.one;
        }

        public static UBlockEntry CreateBlockEntry(UBlocklyPhysic blockPhysic)
        {
            if (!isInit)
                throw new SystemException("BlockFramework did not init");
            UBlockEntry entry = new UBlockEntry(blockPhysic);
            instance.wholeEntries.Add(entry.EntryHash, entry);
            return entry;
        }

        [CanBeNull]
        public static UBlockEntry FindBlockEntry(int entryHash)
        {
            UBlockEntry entry = null;
            instance.wholeEntries.TryGetValue(entryHash, out entry);
            return entry;
        }

        public static void UnLoadBlockEntry(int entryHash)
        {
            var entry = FindBlockEntry(entryHash);
            if (entry != null)
            {
                entry.ClearSpace();
                entry.ClearSideBar();
                ILTranslate.UnRegistBlockEntryApi(entryHash);
            }
            else
            {
                Debug.LogWarning($"UnLoadBlockEntry {entryHash} didnot existed");
            }
        }

        public static void LoadResource<T>(string assetName, System.Action<T> callback) where T : UnityEngine.Object
        {
            instance.loaderSys.LoadResource<T>(assetName, callback);
        }

        public static string GetBlockConfigPath()
        {
            return instance.loaderSys.GetConfigPath();
        }

        public static List<BlockDescribeData> TryParse(IBlockApi blockApi)
        {
            return TranslateHelper.TryParse(blockApi.GetType());
        }

        public static List<BlockDescribeData> TryParse<T>() where T : IBlockApi
        {
            return TranslateHelper.TryParse<T>();
        }

        public static bool IsBlockMethod(System.Reflection.MethodInfo method)
        {
            return TranslateHelper.IsBlockMethod(method);
        }
    }
}